﻿using Core.Sdk.WeiXin.Domain.card;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;

namespace Core.Sdk.WeiXin.Tool
{
    public class JsonHttps
    {
        public static T Get<T>(string url, Merchant math)
        {
            var result = Get(url, math);
            return string.IsNullOrEmpty(result) ? default(T) : JsonConvert.DeserializeObject<T>(result);
        }
        public static string Get(string url, Merchant math)
        {
            Trace.TraceInformation(url);
            var request = CreateRequest(url, "GET");
            SetAuthHeader(math, request);
            var result = string.Empty;
            try
            {
                result = GetData(request);
            }
            catch (WebException ex)
            {
                var res = (HttpWebResponse)ex.Response;
                var sr = new StreamReader(res.GetResponseStream(), Encoding.UTF8);
                result = sr.ReadToEnd();
                sr.Close();
            }
            Trace.TraceInformation(result);
            return result;
        }

        public static string Post(string url, string data, Merchant math)
        {
            Trace.TraceInformation(url);
            Trace.TraceInformation(data);
            var postData = Encoding.UTF8.GetBytes(data);
            var request = CreateRequest(url, "POST");
            var result = string.Empty;

            SetAuthHeader(math, request, data);
            request.ContentLength = postData.Length;
            try
            {
                using (var stream = request.GetRequestStream())
                {
                    stream.Write(postData, 0, postData.Length);
                }
                result = GetData(request);
            }
            catch (WebException ex)
            {
                var res = (HttpWebResponse)ex.Response;
                var sr = new StreamReader(res.GetResponseStream(), Encoding.UTF8);
                result = sr.ReadToEnd();
                sr.Close();
                LogUtil.WriteLog("wechatHttp", $"{url}\r\n{data}\r\n{result}");
            }
            Trace.TraceError(result);
            return result;
        }

        public static string GetData(HttpWebRequest request)
        {
            var result = string.Empty;
            var response = (HttpWebResponse)request.GetResponse();
            var resStream = response.GetResponseStream();
            if (resStream != null)
                result = new StreamReader(resStream).ReadToEnd();
            return result;
        }

        protected static HttpWebRequest CreateRequest(string url, string method)
        {
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = method;
            return request;
        }

        public static void SetAuthHeader(Merchant math, HttpWebRequest request, string postData = "")
        {
            var auth = BuildAuth(request, postData, math);
            request.Headers.Add("Authorization", $"WECHATPAY2-SHA256-RSA2048 {auth}");
            request.Headers.Add("Wechatpay-Serial", math.Cert_No);
            //request.Headers.Add("Wechatpay-Serial", "389B97242C31D9E365DA4484DFF24538E39E78A7");

            request.ContentType = "application/json";
            request.Accept = "application/json";
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36";
        }

        public static string BuildAuth(HttpWebRequest request, string postData, Merchant math)
        {
            string method = request.Method.ToUpper();
            string body = "";
            if (method == "POST" || method == "PUT" || method == "PATCH")
            {
                body = postData;
            }
            string uri = request.RequestUri.PathAndQuery;
            var timestamp = GetTimeStamp();
            string nonce = Path.GetRandomFileName();

            string signStr = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            string signature = RSAHelper.Sign_SHA256(signStr, math.Cert_Path, math.MachId);

            return $"mchid=\"{math.MachId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{math.Cert_No}\",signature=\"{signature}\"";
        }

        public static string Upload(Merchant openMath, string url, string filePath, string postData = "")
        {     
            var result = string.Empty;
            var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");

            var request = CreateRequest(url, "POST");
            SetAuthHeader(openMath, request, postData);
            request.ContentType = "multipart/form-data;boundary=" + boundary;
            Stream reqStream = request.GetRequestStream();
            //表单数据            
            if (postData != "")
            {
                postData = "meta=" + postData;
                string[] arrydata = postData.Split('&');
                var formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\nContent-Type:application/json\r\n\r\n{1}";
                
                foreach (string key in arrydata)
                {
                    reqStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                    string formitem = string.Format(formdataTemplate, key.Split('=')[0].ToString(), key.Split('=')[1].ToString());
                    byte[] formitembytes = Encoding.UTF8.GetBytes(formitem);
                    reqStream.Write(formitembytes, 0, formitembytes.Length);
                }
            }
            reqStream.Write(boundaryBytes, 0, boundaryBytes.Length);
            var header = string.Format("Content-Disposition:form-data;name=\"file\";filename=\"{0}\"\r\nContent-Type:application/image/jpg\r\n\r\n", "file.jpg");
            byte[] headerBytes = Encoding.UTF8.GetBytes(header);
            reqStream.Write(headerBytes, 0, headerBytes.Length);

            int index = 0;
            byte[] buffer = new byte[4096];
            using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                while ((index = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    reqStream.Write(buffer, 0, index);
                }
            }
            reqStream.Write(boundaryBytes, 0, boundaryBytes.Length);
            reqStream.Close();
            
            try
            {
                var response = request.GetResponse();
                var resStream = response.GetResponseStream();
                result = new StreamReader(resStream).ReadToEnd();
                resStream.Close();
            }
            catch (WebException ex)
            {
                var res = (HttpWebResponse)ex.Response;
                var myResponseStream = res.GetResponseStream();
                var sr = new StreamReader(myResponseStream, Encoding.UTF8);
                result = sr.ReadToEnd();
                sr.Close();
            }
            return result;
        }

        private static int GetTimeStamp()
        {
            var utcNow = DateTime.Now;
            var timeSpan = utcNow - new DateTime(1970, 1, 1, 8, 0, 0);
            return (int)timeSpan.TotalSeconds;
        }
    }
}